package gstudio.format;

import gstudio.data.IData;
import gstudio.images.MyImage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IViewPart;

public class StyleManager {

	private static StyleManager styleManager;

	public static StyleManager getInstance() {
		if (styleManager == null)
			styleManager = new StyleManager();
		return styleManager;
	}

	private String formatText = "";

	private List<Format> formatList;

	private Map<String, Format> formatPrefixMap = new HashMap<String, Format>();

	private Map<String, Format> formatPostfixMap = new HashMap<String, Format>();
	private Display display = Display.getDefault();

	public StyleManager() {

		formatList = new ArrayList<Format>();
		{
			StyleRange sr = new StyleRange();
			Format format = new Format("", "", sr);
			format.setChange(0);
			format.setName("Clear");
			format.setBackground(display.getSystemColor(22));
			format.setImageName("clear.png");
			formatList.add(format);
		}
		{
			StyleRange sr = new StyleRange();
			sr.foreground = this.display.getSystemColor(9);
			Format format = new Format("§$1+", "§$1-", sr);
			format.setName("Blue");
			format.setImageName("frontBlue.png");
			formatList.add(format);
		}
		{
			StyleRange sr = new StyleRange();
			sr.foreground = this.display.getSystemColor(3);
			Format format = new Format("§$2+", "§$2-", sr);
			format.setName("Red");
			format.setImageName("frontRed.png");
			formatList.add(format);
			format.setId(2);
		}
		{
			StyleRange sr = new StyleRange();
			sr.foreground = this.display.getSystemColor(16);
			Format format = new Format("§$7+", "§$7-", sr);
			format.setName("Gray");
			format.setImageName("fontGray.png");
			formatList.add(format);
			format.setId(2);
		}
		{
			StyleRange sr = new StyleRange();
			sr.background = this.display.getSystemColor(7);
			Format format = new Format("§$4+", "§$4-", sr);
			format.setName("Yellow");
			format.setImageName("yellowBack.png");
			formatList.add(format);
		}
		{
			StyleRange sr = new StyleRange();
			sr.background = this.display.getSystemColor(5);
			Format format = new Format("§$5+", "§$5-", sr);
			format.setName("Green");
			format.setImageName("greenBack.png");
			formatList.add(format);
		}
		{
			StyleRange sr = new StyleRange();
			sr.underline = true;
			Format format = new Format("§$6+", "§$6-", sr);
			format.setName("Underline");
			format.setImageName("underline.ico");
			formatList.add(format);
		}
		{
			StyleRange sr = new StyleRange();
			sr.strikeout = true;
			Format format = new Format("§$8+", "§$8-", sr);
			format.setName("Strikeout");
			format.setImageName("s.gif");
			formatList.add(format);
		}
		{
			StyleRange sr = new StyleRange();
			sr.fontStyle = 1;
			Format format = new Format("§$3+", "§$3-", sr);
			format.setName("Bold");
			format.setImageName("bold.ico");
			formatList.add(format);
		}
		for (Format f : formatList) {
			addMapping(f);
		}
	}

	public void addMapping(Format format) {
		this.formatPrefixMap.put(format.getPrefix(), format);
		this.formatPostfixMap.put(format.getPostfix(), format);
	}

	public StyleRange copyStyleRange(StyleRange sr) {
		StyleRange sr1 = new StyleRange();
		sr1.foreground = sr.foreground;
		sr1.background = sr.background;
		sr1.font = sr.font;
		sr1.fontStyle = sr.fontStyle;
		sr1.strikeout = sr.strikeout;
		sr1.underline = sr.underline;
		return sr1;
	}

	public Image createImage(Color background) {
		Image image = new Image(Display.getCurrent(), 16, 16);
		GC gc = new GC(image);
		gc.setBackground(background);
		gc.fillRectangle(image.getBounds());
		gc.dispose();
		return image;
	}

	public boolean isGB(char c) {
		return (c >= '一') && (c <= 40891);
	}

	public void setEditorToolBar(IViewPart view, final StyledText styledText) {

		IToolBarManager toolBarManager = view.getViewSite().getActionBars()
				.getToolBarManager();

		for (Format f : formatList) {
			final StyleRange styleRang = f.getStyleRange();
			Action action = new Action() {
				public void run() {
					StyleRange sr = null;
					if (styleRang != null) {
						sr = copyStyleRange(styleRang);
					}
					if (sr == null) {
						sr = new StyleRange();
					}
					int[] selectR = styledText.getSelectionRanges();
					sr.start = selectR[0];
					sr.length = selectR[1];
					styledText.setStyleRange(sr);
				}
			};
			action.setText(f.getName());
			action.setImageDescriptor(new MyImage().get(f.getImageName()));
			toolBarManager.add(action);
		}

		// 格式化文本
		Action formatTextAction = new Action("Format Text") {
			public void run() {
				String str = styledText.getText();
				String out = "";
				int i;
				char pre = 0;
				for (char c : str.toCharArray()) {
					i = (int) c;
					// System.out.println(i + ">" + c + "<");

					// 如果当前是换行
					if (i == 10 || i == 13) {
						// 如果前面是点，则是分段，否则只是空格
						if (pre == '.') {
							out += "\n\n";
						} else if (pre != 10 && pre != 13) {
							out += " ";
						}
					} else {
						out += c;
					}
					pre = c;
				}
				styledText.setText(out);
			}
		};

		toolBarManager.add(new Separator());
		formatTextAction.setImageDescriptor(new MyImage().get("refresh.png"));
		toolBarManager.add(new Separator());
		toolBarManager.add(formatTextAction);

	}

	public void setStyledText(StyledText styledText, String in) {
		styledText.setText("");
		StringBuffer out = new StringBuffer();

		List<StyleRange> tempRangeList = new ArrayList<StyleRange>();
		List<StyleRange> styleRangeList = new ArrayList<StyleRange>();
		int index = 0;
		int endIndex = 0;

		this.formatText = "";
		String oneChar = "";
		for (char c : in.toString().toCharArray()) {
			oneChar = Character.toString(c);

			if (c == '§') {
				if (!this.formatText.equals("")) {
					out.append(this.formatText);
					index += this.formatText.length();
					endIndex = index;
					this.formatText = "";
				}
				this.formatText += c;
			} else if (!this.formatText.equals("")) {
				this.formatText += oneChar;

				if (this.formatText.length() > 10) {
					out.append(this.formatText);
					index += this.formatText.length();
					endIndex = index;
					this.formatText = "";
				} else if (textIsFormat() == 1) {
					Format format = (Format) this.formatPrefixMap
							.get(this.formatText);

					if (format != null) {
						StyleRange sr = copyStyleRange(format.getStyleRange());
						sr.start = index;
						tempRangeList.add(sr);
					}
					this.formatText = "";
				} else {
					if (textIsFormat() != 2) {
						continue;
					}
					StyleRange sr = (StyleRange) tempRangeList
							.get(tempRangeList.size() - 1);
					sr.length = (endIndex - sr.start + 1);
					styleRangeList.add(sr);
					tempRangeList.remove(sr);
					this.formatText = "";
				}
			} else {
				out.append(oneChar);
				endIndex = index;
				index++;
			}
		}

		out.append(this.formatText);
		styledText.append(out + "");
		styledText.setStyleRanges((StyleRange[]) styleRangeList
				.toArray(new StyleRange[styleRangeList.size()]));
	}

	public String styledText2String(StyledText styledText) {
		String out = "";

		StyleRange last = null;
		for (StyleRange sr : styledText.getStyleRanges()) {
			if ((last != null) && (last.start + last.length == sr.start)
					&& (styleRangeCompare(last, sr))) {
				last.length += sr.length;
				styledText.setStyleRange(last);
			} else {
				last = sr;
			}
		}
		String input = styledText.getText();

		int normalTextStart = 0;

		for (StyleRange sr : styledText.getStyleRanges()) {
			out = out + input.substring(normalTextStart, sr.start);
			normalTextStart = sr.start + sr.length;

			for (String prefix : this.formatPostfixMap.keySet()) {
				Format format = (Format) this.formatPostfixMap.get(prefix);
				if ((format == null)
						|| (!styleRangeCompare(sr, format.getStyleRange())))
					continue;
				String addStr = format.getPrefix()
						+ input.substring(sr.start, sr.start + sr.length)
						+ format.getPostfix();
				out = out + addStr;
			}

		}

		out = out + input.substring(normalTextStart);
		return out;
	}

	public boolean styleRangeCompare(StyleRange sr1, StyleRange sr2) {
		boolean b = true;
		String s = "";
		if (sr1.background != sr2.background) {
			s = s + sr1.background + " " + sr2.background;
			b = false;
		}
		if (sr1.fontStyle != sr2.fontStyle) {
			s = s + sr1.fontStyle + " " + sr2.fontStyle;
			b = false;
		}
		if (sr1.font != sr2.font) {
			s = s + sr1.font + " " + sr2.font;
			b = false;
		}
		if (sr1.foreground != sr2.foreground) {
			s = s + sr1.foreground + " " + sr2.foreground;
			b = false;
		}
		if (sr1.strikeout != sr2.strikeout) {
			s = s + sr1.strikeout + " " + sr2.strikeout;
			b = false;
		}
		if (sr1.underline != sr2.underline) {
			s = s + sr1.underline + " " + sr2.underline;
			b = false;
		}

		return b;
	}

	private int textIsFormat() {
		int i = 0;
		if (this.formatPrefixMap.get(this.formatText) != null) {
			i = 1;
		}

		if (this.formatPostfixMap.get(this.formatText) != null) {
			i = 2;
		}

		return i;
	}
	
	
	public StyledText getStyleTextControl(Composite mainComp) {
		StyledText styledText = new StyledText(mainComp, SWT.MULTI | SWT.WRAP
				| SWT.V_SCROLL);
		styledText.setMargins(10, 10, 10, 10);
		{
			GridData gd = new GridData(GridData.FILL_BOTH);
			styledText.setLayoutData(gd);
		}
		{
			FontData[] fontData = new FontData[] { new FontData("Arial", 11,
					SWT.NORMAL) };
			styledText.setFont(new Font(null, fontData));
		}

		return styledText;
	}

	// 保存内容 @Override
	public void styledTextSaveToIData(IData currentData, StyledText styledText) {
		if (currentData == null)
			return;

		String content = styledText2String(
				styledText);
		currentData.setValueOf("content", content);
	}

}
